/*
--------------------------------------------------------------------------------
				Ak-Lib. 
			 Project       	: Ak-Lib
			 Group         	: Ak-Lib R&D Team
			 Author        	: Ocean.Wang
			 Create Date 	: 05-01-2010
--------------------------------------------------------------------------------
Code Name 	:  A.K 	~v~
Description	:  Yet Another Cross-Platform Lib.
Cautions    	:
--------------------------------------------------------------------------------
Change History:
Version		: 0.1
Building 		: 05/01/10
10-05.01 first draft, build, debug and test.
--------------------------------------------------------------------------------
*/

#include "ak_sctp.h"

static 	int 	_gTraceLvl_Sctp = TRACELVL_WARNING;

int 	SSctp_SetTraceLvl(int lvl)
{
	int 	ret = -1;
	
	switch(lvl){
		case TRACELVL_FATAL:
		case TRACELVL_ERROR:
		case TRACELVL_WARNING:
		case TRACELVL_NORMAL:
		case TRACELVL_DEBUG:
		case TRACELVL_ALL:
			_gTraceLvl_Sctp = lvl;
			ret = 0;
			break;
		default:
			break;
	}

	return ret;
}

int 	SSctp_GetTraceLvl(void)
{
	return  _gTraceLvl_Sctp;
}

/* -----------------------------------------------------------------------
**	SCTP Socket 1
**	Send.
**	Receive 1: Wait till Data Arrive.
**	Receive 2: Wait till Timeout.
**	
*/
#define SYS_SCTP_RE_WR 		0X5		/* Write Delay Cnt */
#define SYS_SCTP_TO_WR 		0X1		/* Write Delay Time */
#define SYS_SCTP_BUF_MAX 	0X10000

int 	SockSctp_Tx(int 				sockId, 				
					unsigned char 	* 	pMsg, 	
					int 				msgLen,
					S_SOCKET_ADDRIN *	pSockAddr)
{
	int 				ret, retry, flag;
	struct msghdr 		ioHead;
	struct iovec  		ioVec[1];

	if((!pSockAddr) || (!pMsg) || (msgLen <= 0) || (sockId == -1)){
		return -1;
	}

	/* IoVec */
	ioVec[0].iov_base 	= pMsg;
	ioVec[0].iov_len 	= msgLen;

	/* IoHead */
	ioHead.msg_flags 	= 0; 		
	ioHead.msg_control 	= NULL;		
	ioHead.msg_controllen= 0;		
	ioHead.msg_iov 		= ioVec;	
	ioHead.msg_iovlen 	= 1;	
	ioHead.msg_name 	= pSockAddr;
	ioHead.msg_namelen 	= sizeof(S_SOCKET_ADDRIN);	

	retry	= 0;
	do{
		flag 	= 0;
		ret 	= sendmsg(sockId, &ioHead, 0);
		if(ret == -1){
			switch(errno){
				case EWOULDBLOCK:
				case EINTR:
					/* Here We Delay for a While */
					if(retry < SYS_SCTP_RE_WR){
						retry++;
						SYS_SLEEP(SYS_SCTP_TO_WR);
						flag = 1;
					}
					break;

				case EAFNOSUPPORT:
				case EBADF:
				case ENOTCONN:
				case ENOTSOCK:
				case EOPNOTSUPP:
				case EPIPE:	
				case EIO:
				case ELOOP:
				case ENAMETOOLONG:
				case ENOENT:
				case ENOTDIR:
				case EACCES:
				case EDESTADDRREQ:
				case EHOSTUNREACH:
				case EINVAL:
				case EISCONN:
					return -1;
					break;

				case ENETDOWN:
				case ENETUNREACH:
				case ECONNRESET:
				case ECONNREFUSED:
					/* Net Down | UnReach | Close ? */
					/* Net UnReach */
					return -1;
					break;
					
				case EMSGSIZE:
				case ENOBUFS:
				case ENOMEM:
					/* Size Memory ? */
					return -1;
					break;
					
				default:
					SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_ERROR, "SockSend SCTP:[%d] Err:[%d]\n", sockId, errno);
					return -1;
					break;
			}
		}
	}while(flag == 1);

	return 0;
}


int 	SockSctp_Rx(int 			sockId, 
					_t_cbentry * 	pCbEntry)
{
	int 				ret, flag;
	socklen_t			vSockLen;
	S_SOCKET_ADDRIN	vSockAddr;

	unsigned char 		vBuf[SYS_SCTP_BUF_MAX];

	if(sockId == -1){
		return -1;
	}

	/* Let's Consume all the Data First */
	flag = 1;
	while(flag == 1){
		#if 0
		SYS_MEMZERO(&vSockAddr, sizeof(vSockAddr));
		#endif
		vSockLen = sizeof(S_SOCKET_ADDRIN);	
		ret=recvfrom(sockId, vBuf, SYS_SCTP_BUF_MAX, 0, 
					(struct  sockaddr *)(&vSockAddr), &vSockLen);
		if (ret > 0) {
			/* Data read from the socket */
			if(pCbEntry && (pCbEntry->cbProc)){
				if(pCbEntry->cbProc(pCbEntry->pArg, 
									pCbEntry->lArg, 
									vBuf, ret,
									&vSockAddr) == -1){
					/* We Recv the Left*/
					SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_DEBUG, "SockRecv SCTP:[%d] CallBack Fail!\n", 
						sockId);
				}
			}
			continue;
		}
		else if (ret == -1) {
			/* Error, check errno, take action... */
			switch(errno){
				case EWOULDBLOCK:
					flag = 0;
					break;
					
				case ENOTSOCK:
					return -1;
					break;
					
				case EINTR:
					break;
					
				case ECONNRESET:
				case EINVAL:
				case ENOTCONN:
				case EOPNOTSUPP:
				case ETIMEDOUT:
				default:
					SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_ERROR, "SockRecv SCTP:[%d] Read Error:[%d]\n", 
						sockId, errno);
				  	return -1;
					break;
			}
		} 
		else if (ret == 0) {
		  	/* Peer closed the socket, finish the close */
			SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_WARNING, "SockRecv SCTP:[%d] Peer Close\n", sockId);
		  	return -1;
		}	
	}

	return 0;	
}

int 	SockSctp_RxSel(int 			sockId, 
						_t_cbentry * 	pCbEntry, 
						int 			timeout)
{
	int 				ret;
	fd_set 		 		vFdSet;
	struct 	timeval 	vSockTv;
	fd_set 		*		pFdSet;
	
	if(sockId == -1){
		return -1;
	}
	
	/* Let's Init Select & TimeOut*/
	pFdSet = &(vFdSet);
	FD_ZERO	(pFdSet);
	FD_SET	(sockId, pFdSet);
	
	vSockTv.tv_sec 	= (timeout/1000);
	vSockTv.tv_usec = (timeout%1000) * 1000 ;

	/* Select */
__SOCKRXSEL_AGAIN_SCTP:
	ret = select(sockId+1, pFdSet, NULL, NULL, (struct timeval *)(&vSockTv));

	if((ret > 0) && (FD_ISSET(sockId, pFdSet))){
		/* Let's Consume all the Data */
		ret = SockSctp_Rx(sockId, pCbEntry);
	}
	else if(ret == 0){
		SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_WARNING, "SockRecv SCTP:[%d] Select TimeOut\n", sockId);
		return -1;
	}
	else { 
		switch(errno){
			case EBADF:
				/* Here the FD is Error! */
				return -1;
				break;
				
			case EINTR:
				goto __SOCKRXSEL_AGAIN_SCTP;
				break;
				
			case EINVAL:
			case ENOMEM:
			default:
				return -1;
				break;
		}
	}
	return ret;
}


/* -----------------------------------------------------------------------
**	SCTP Socket Config
*/

S_SOCKET 	SockSctp_Open(unsigned int ip, unsigned short port, _t_sockSCTP_Cfg * config, int bBind)
{
	int 				ret;
	S_SOCKET_ADDRIN 	sockAddr;
	S_SOCKET 			sock;
	struct sctp_initmsg 		initMsg;
	struct sctp_event_subscribe event;
	
	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
	
	if (sock != S_SOCKET_INVALID){
		/* Socket Opt */
		SockSet_Linger(sock);

		/* SCTP Opt : Initial */
		SYS_MEMZERO(&initMsg, sizeof(struct sctp_initmsg));
		ret = sizeof(struct sctp_initmsg);
		ret = getsockopt(sock,IPPROTO_SCTP,SCTP_INITMSG, &initMsg,(unsigned int *)(&ret));
		initMsg.sinit_max_instreams  = config->maxStm_In;
		initMsg.sinit_num_ostreams	 = config->maxStm_Out;
		initMsg.sinit_max_attempts	 = config->max_Attempt;
		initMsg.sinit_max_init_timeo = config->RTO_Initial;
		ret = setsockopt(sock, IPPROTO_SCTP,SCTP_INITMSG, &initMsg,sizeof(struct sctp_initmsg));

		/* SCTP Opt : IO Event */
		SYS_MEMZERO(&event, sizeof(struct sctp_event_subscribe));
		event.sctp_data_io_event 		= 1;
		event.sctp_association_event 	= 1;
		event.sctp_address_event 		= 1;
		event.sctp_send_failure_event 	= 1;
		event.sctp_peer_error_event 	= 1;
		event.sctp_shutdown_event 		= 1;
		ret = setsockopt(sock,IPPROTO_SCTP,SCTP_EVENTS,&event, sizeof(struct sctp_event_subscribe));
		
		/* Binding */
		if(bBind == _F_YES){
			/* Associate a local address with the socket */
			S_ADDRIN_INIT(sockAddr, ip, port);
			if(S_SOCKET_ERROR == bind(sock, (S_SOCKET_ADDR*)&sockAddr, sizeof(S_SOCKET_ADDRIN))){
				S_SOCKET_CLOSE( sock );
				return S_SOCKET_INVALID;
			}
		}
	}
	
	return sock;
}


int 	SockSctp_Peer(S_SOCKET sock, int assocId)
{
	int 	i, ret;
    S_SOCKET_ADDR * addrs;
	
	ret = sctp_getpaddrs(sock, (sctp_assoc_t)assocId, (&addrs));
	if (ret <= 0){
		SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_ERROR, "Sock:[%d]:(%d) Get Peer Error.\n", sock, assocId);
	}
	else{
		for(i=0; i<ret; i++){
			SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_ERROR, "Sock:[%d]:(%d) Get Peer<%d> : .\n", 
				sock, assocId, i);
		}
		sctp_freepaddrs(addrs);
	}

	return ret;
}


int 	SockSctp_Close(S_SOCKET sock,  int assocId)
{
	int 	ret;
    struct sctp_sndrcvinfo sndrcvInfo;
	
	SYS_MEMZERO(&sndrcvInfo, sizeof(struct sctp_sndrcvinfo));
	
	sndrcvInfo.sinfo_assoc_id 	= (sctp_assoc_t)assocId;
	sndrcvInfo.sinfo_flags 		|= SCTP_EOF;
	ret = sctp_send(sock, (const void *)NULL, 0, &sndrcvInfo, MSG_DONTWAIT);
	close(sock);
	return ret;	
}


int 	SockSctp_Connect(S_SOCKET sock, unsigned int ip, unsigned short port, _e_sockState * rState)
{
	int 				ret;
	_u_ipport 			local, remote;
	_e_sockState 		state;
	S_SOCKET_ADDRIN		sockAddr;
	socklen_t 			sockLen;

	ret 	= -1;
	*rState = SOCKST_NUL;
	if((sock  != S_SOCKET_INVALID)){
		S_SOCK_SET_NONBLOCK(sock, ret);
		sockAddr.sin_family 		= AF_INET;
		sockAddr.sin_port			= htons(port);
		sockAddr.sin_addr.s_addr	= htonl(ip);
		sockLen = sizeof(S_SOCKET_ADDRIN);
		ret 	= connect(sock, &sockAddr, sockLen);
		state	= SOCKST_CONN;
		if(ret == -1){
			switch(errno){
				case EINPROGRESS:
			#if 0
					SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_ERROR, "SockConnF:[%d] Err:[%d]\n", sock, errno);
			#endif
					ret = 0;
					break;
		
				case EACCES:
				case EPERM:
				case EADDRINUSE:
				case EAFNOSUPPORT:
				case EAGAIN:
				case EALREADY:
				case EBADF:
				case ECONNREFUSED:
				case EFAULT:
				case EINTR:
				case EISCONN:
				case ENETUNREACH:
				case ENOTSOCK:
				case ETIMEDOUT:
				default:
					SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_ERROR, "SockConnect:[%d] Err:[%d]\n", sock, errno);
					break;
			}
		}
		else{
			#if 0
			SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_ERROR, "SockConnS:[%d] Err:[%d]\n", sock, errno);
			#endif
			state = SOCKST_OK;
		}
		if(ret == 0){
			*rState = state;
			/* Remote Part */
			_IPPORT_GEN(&remote, 
						sockAddr.sin_addr.s_addr,
						sockAddr.sin_port);
			/* Local Part */
			getsockname(sock, (S_SOCKET_ADDR *)(&sockAddr), &sockLen);
			_IPPORT_GEN(&local, 
						sockAddr.sin_addr.s_addr,
						sockAddr.sin_port);
		}
	}
	
	return ret;
}


int 	SockSctp_Accept(S_SOCKET 	sock, _t_cbentry * pCbEntry)
{
	socklen_t 			sockLen;
	S_SOCKET 			sockGen;
	S_SOCKET_ADDRIN		sockAddr;
	_u_ipport 			local, remote;
	int 				flag,  ret;
	do{
		flag = 1;
		
		sockLen = sizeof(S_SOCKET_ADDRIN);
		sockGen = accept(sock, (struct sockaddr *) &sockAddr, &sockLen);
		if(sockGen == -1){
			flag = 0;
			switch(errno){
				case EWOULDBLOCK:
					break;
		
				case EBADF:
				case EINTR:
				case EINVAL:
				case EFAULT:
				case ENOTSOCK:
				case EOPNOTSUPP:
				case EPROTO:
				case ENOPROTOOPT:
				case EMFILE:
				case ENFILE:
				case ENOBUFS:
				case ENOMEM:
				case EPERM:
				case ENOSR:
				case ESOCKTNOSUPPORT:
				case EPROTONOSUPPORT:
				case ETIMEDOUT: 
				case ENETDOWN:
				case ENETUNREACH:
				case EHOSTUNREACH:
				case EHOSTDOWN:
				case ENONET:
				default:
					SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_ERROR, "Sock:[%d] AcceptErr:[%d]\n", sock, errno);
					break;
			}
		}
		else{
			/* Remote Part */
			_IPPORT_GEN(&remote, 
						sockAddr.sin_addr.s_addr,
						sockAddr.sin_port);
			/* Local Part */
			getsockname(sockGen, (S_SOCKET_ADDR *)(&sockAddr), &sockLen);
			_IPPORT_GEN(&local, 
						sockAddr.sin_addr.s_addr,
						sockAddr.sin_port);
			S_SOCK_SET_NONBLOCK(sockGen, ret);
			SockSet_Linger(sockGen);
			
			/* Here We Should Add the Call Back for Accept Event */
			ret = -1;
			if(pCbEntry && (pCbEntry->cbProc)){
				ret = pCbEntry->cbProc(	pCbEntry->pArg, 
										pCbEntry->lArg,
										sockGen);
			}
		}
	}while(flag == 1);
	
	return -1;
}


static 	int 	SockSctp_EvtHandle(S_SOCKET sock, union sctp_notification * pNotify)
{
	int 	ret;
	struct sctp_assoc_change	*eAssoc;
	struct sctp_send_failed 	*eSendF;
    struct sctp_shutdown_event  *eShutDown;
	struct sctp_remote_error 	*eRemote;
	
	struct sctp_paddr_change 	*ePAddrChg;
	struct sockaddr_storage 	*pSas;
    S_SOCKET_ADDRIN 			*pSin;       
	S_SOCKET_ADDRIN6 			*pSin6;
	char 						sAddr[INET6_ADDRSTRLEN];
	
	sctp_assoc_t 	assocId;

	ret = -1;
	switch (pNotify->sn_header.sn_type){
		
		case SCTP_ASSOC_CHANGE:
			eAssoc = &(pNotify->sn_assoc_change);
			assocId = (eAssoc->sac_assoc_id);

			switch(eAssoc->sac_state){
				case SCTP_COMM_UP:
					SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_WARNING, "SockComm:[%d] Up\n", assocId);
					break;
				case SCTP_RESTART:
					SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_WARNING, "SockComm:[%d] Restart\n", assocId);
					break;					
				case SCTP_COMM_LOST:
					SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_WARNING, "SockComm:[%d] Lost\n", assocId);
					break;						
				case SCTP_SHUTDOWN_COMP:
					SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_WARNING, "SockComm:[%d] ShutDown\n", assocId);
					break;						
				case SCTP_CANT_STR_ASSOC:
					SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_WARNING, "SockComm:[%d] Setup\n", assocId);
					break;						
				default:
					SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_WARNING, "SockComm:[%d] (%d)\n", assocId, eAssoc->sac_state);
					break;
			}
			ret = 0;
			break;
			
		case SCTP_SEND_FAILED:
			eSendF = &(pNotify->sn_send_failed);
			assocId = (eSendF->ssf_assoc_id);

			SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_NORMAL, "SockSend:[%d] Fail\n", assocId);
			break;
			
		case SCTP_PEER_ADDR_CHANGE:
			ePAddrChg = &(pNotify->sn_paddr_change);
			assocId = (ePAddrChg->spc_assoc_id);

            pSas = &(ePAddrChg->spc_aaddr);             
			if (pSas->ss_family == AF_INET) {               
				pSin = (S_SOCKET_ADDRIN *)(pSas);               
				inet_ntop(AF_INET, &(pSin->sin_addr),  sAddr, INET6_ADDRSTRLEN);             
			} 
			else {               
				pSin6 = (S_SOCKET_ADDRIN6 *)(pSas);               
				inet_ntop(AF_INET6, &(pSin6->sin6_addr), sAddr, INET6_ADDRSTRLEN);            
			}             
			SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_NORMAL, "SockAddr:[%d] Peer Change\n", assocId);
			break;
			
		case SCTP_REMOTE_ERROR:
			eRemote = &(pNotify->sn_remote_error);
			assocId = (eRemote->sre_assoc_id);

			SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_NORMAL, "SockRemote:[%d] Error\n", assocId);
			break;
			
		case SCTP_SHUTDOWN_EVENT:
			eShutDown = &(pNotify->sn_shutdown_event);
			assocId = (eShutDown->sse_assoc_id);

			SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_NORMAL, "SockShut:[%d] Down\n", assocId);
			break;
			
		default:
			SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_NORMAL, "Sock?: Error (%d)\n", pNotify->sn_header.sn_type);
			break;
	}
	
	return ret;
}


int 	SockSctp_Recv(int 	sockId, _t_cbentry * pCbEntry)
{
	int 					ret, flag, msgFlag, msgAvail;
    struct sctp_sndrcvinfo 	sndrcvInfo;
	unsigned int 			ppId;
	
	socklen_t				vSockLen;
	S_SOCKET_ADDRIN			vSockAddr;
	unsigned char 			vBuf[SYS_SCTP_BUF_MAX];
	
	if(sockId == S_SOCKET_INVALID){
		return -1;
	}

	/* Let's Consume all the Data First */
	flag 	= 1;
	msgAvail= 1;
	while(flag == 1){
		#if 0
		SYS_MEMZERO(&vSockAddr, sizeof(vSockAddr));
		SYS_MEMZERO(&sndrcvInfo, sizeof(struct sctp_sndrcvinfo));
		#endif
		vSockLen = sizeof(S_SOCKET_ADDRIN);	
		ret=sctp_recvmsg(sockId, 
						vBuf, SYS_SCTP_BUF_MAX, 
						(struct  sockaddr *)(&vSockAddr), &vSockLen,
						&sndrcvInfo, &msgFlag);
		if (ret > 0) {
			if(msgFlag & MSG_NOTIFICATION){
				SockSctp_EvtHandle(sockId, (union sctp_notification *)vBuf);
			}
			/* In Fact, We must be Aware of the StreamID, the Partial Flag is Combine to Stream */
			else if(msgFlag & MSG_EOR){
				if(msgAvail == 1){
					ppId = sndrcvInfo.sinfo_ppid;
					ppId = ntohl(ppId);
					/* Data read from the socket */
					if(pCbEntry && (pCbEntry->cbProc)){
						if(pCbEntry->cbProc(pCbEntry->pArg, 
											pCbEntry->lArg, 
											vBuf, ret,
											&vSockAddr, ppId) == -1){
											
							/* We Recv the Left*/
							SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_DEBUG, "SockRecv SCTP:[%d] CallBack Fail!\n", 
								sockId);
						}
					}
				}else{
					msgAvail = 1;
				}
			}
			else{
				/* Not Enough Buffer ? */
				msgAvail = 0;
			}
			continue;
		}
		else if (ret == -1) {
			/* Error, check errno, take action... */
			switch(errno){
				case EWOULDBLOCK:
					flag = -1;
					break;
					
				case ENOTSOCK:
					return -1;
					break;
					
				case EINTR:
					break;
					
				case ECONNRESET:
				case EINVAL:
				case ENOTCONN:
				case EOPNOTSUPP:
				case ETIMEDOUT:
				default:
					SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_ERROR, "SockRecv SCTP:[%d] Read Error:[%d]\n", 
						sockId, errno);
				  	return -1;
					break;
			}
		} 
		else if (ret == 0) {
		  	/* Peer closed the socket, finish the close */
			SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_WARNING, "SockRecv SCTP:[%d] Peer Close\n", sockId);
		  	return -1;
		}	
	}

	return -1;	
}


int 	SockSctp_Send(int 	sockId, unsigned char * pMsg, int msgLen, 
							S_SOCKET_ADDRIN * pSockAddr, unsigned int ppId)
{
	int 				ret, retry, flag;
	retry	= 0;
	ppId = htonl(ppId);
	do{
		flag 	= 0;
		ret 	= sctp_sendmsg(sockId, pMsg, msgLen, 
								(S_SOCKET_ADDR *)pSockAddr, sizeof(S_SOCKET_ADDRIN),
								ppId,
								0, 0, 0, 0);
		if(ret == -1){
			switch(errno){
				case EWOULDBLOCK:
				case EINTR:
					/* Here We Delay for a While */
					if(retry < SYS_SCTP_RE_WR){
						retry++;
						SYS_SLEEP(SYS_SCTP_TO_WR);
						flag = 1;
					}
					break;

				case EAFNOSUPPORT:
				case EBADF:
				case ENOTCONN:
				case ENOTSOCK:
				case EOPNOTSUPP:
				case EPIPE:	
				case EIO:
				case ELOOP:
				case ENAMETOOLONG:
				case ENOENT:
				case ENOTDIR:
				case EACCES:
				case EDESTADDRREQ:
				case EHOSTUNREACH:
				case EINVAL:
				case EISCONN:
					return -1;
					break;

				case ENETDOWN:
				case ENETUNREACH:
				case ECONNRESET:
				case ECONNREFUSED:
					/* Net Down | UnReach | Close ? */
					/* Net UnReach */
					return -1;
					break;
					
				case EMSGSIZE:
				case ENOBUFS:
				case ENOMEM:
					/* Size Memory ? */
					return -1;
					break;
					
				default:
					SYS_TRACE(_gTraceLvl_Sctp, TRACELVL_ERROR, "SockSend SCTP:[%d] Err:[%d]\n", sockId, errno);
					return -1;
					break;
			}
		}
	}while(flag == 1);

	return 0;
}
